//import java.util.LinkedList;
import java.util.Random;
import java.util.Vector;


public class HMM {

//	public static int MIGRATING = 0;
//	public static int QUACKING = 1;
//	public static int PANICKING = 2;
//	public static int FEIGNING_DEATH = 3;
	
	private static int NUMSTATES = 3;
	private int NUMOBSERVATION = 9;
	private boolean validStateSeq = false;
//	private int numErrors = 0;
//	private int numErrorsG = 0;
	//private int NUM_MIGRATING_OBSERVATION = 0;
	//private int NUM_QUACKING_OBSERVATION = 0;
	//private int NUM_PANICKING_OBSERVATION = 0;
	//private int NUM_FEIGNING_OBSERVATION = 0;
	
	private static int MIGRATING = 0;
	private static int PANICKING = 1;
	private static int FEIGNING_DEATH = 2;
	private static int QUACKING = 3;
	
	private Vector<Vector<Integer>> typMax = new Vector<Vector<Integer>>();
	
	private double[][] A;
	private double[][] B;
	private double[] pi;
	
	private Vector<Integer> existingActions = new Vector<Integer>();
	private double[] whichState = new double[NUMSTATES];
	private int isConverged = 0;
	
	public HMM(Duck duck, int maxTime, Deadline pDue)
	{
		
		initializeExistingActions();
		typMax.add(new Vector<Integer>());
		typMax.get(MIGRATING).add(this.transFormObservation(new Action(0, Action.ACTION_KEEPSPEED,Action.ACTION_STOP, 0)));
		typMax.get(MIGRATING).add(this.transFormObservation(new Action(0, Action.ACTION_ACCELERATE,Action.ACTION_STOP, 0)));
		typMax.add(new Vector<Integer>());
		typMax.get(PANICKING).add(this.transFormObservation(new Action(0,Action.ACTION_ACCELERATE, Action.ACTION_ACCELERATE, 0)));
		typMax.get(PANICKING).add(this.transFormObservation(new Action(0,Action.ACTION_KEEPSPEED, Action.ACTION_ACCELERATE, 0)));
		typMax.get(PANICKING).add(this.transFormObservation(new Action(0,Action.ACTION_ACCELERATE, Action.ACTION_KEEPSPEED, 0)));
		typMax.get(PANICKING).add(this.transFormObservation(new Action(0,Action.ACTION_STOP, Action.ACTION_ACCELERATE, 0)));
		typMax.get(PANICKING).add(this.transFormObservation(new Action(0,Action.ACTION_ACCELERATE, Action.ACTION_STOP, 0)));
		typMax.add(new Vector<Integer>());
		typMax.get(FEIGNING_DEATH).add(this.transFormObservation(new Action(0,Action.ACTION_STOP, Action.ACTION_ACCELERATE, 0)));
		typMax.get(FEIGNING_DEATH).add(this.transFormObservation(new Action(0,Action.ACTION_KEEPSPEED, Action.ACTION_ACCELERATE, 0)));
		//typMax.get(FEIGNING_DEATH).add(this.transFormObservation(new Action(0,Action.ACTION_ACCELERATE, Action.ACTION_ACCELERATE, 0)));
		typMax.get(FEIGNING_DEATH).add(this.transFormObservation(new Action(0,Action.ACTION_STOP, Action.ACTION_KEEPSPEED, 0)));
		typMax.add(new Vector<Integer>());
		typMax.get(QUACKING).add(this.transFormObservation(new Action(0,Action.ACTION_KEEPSPEED, Action.ACTION_STOP, 0)));
		typMax.get(QUACKING).add(this.transFormObservation(new Action(0,Action.ACTION_STOP, Action.ACTION_KEEPSPEED, 0)));
		typMax.get(QUACKING).add(this.transFormObservation(new Action(0,Action.ACTION_STOP, Action.ACTION_STOP, 0)));
		typMax.get(QUACKING).add(this.transFormObservation(new Action(0,Action.ACTION_KEEPSPEED, Action.ACTION_KEEPSPEED, 0)));
		NUMOBSERVATION = this.existingActions.size();
		for (int i = 0; i < whichState.length; i++)
		{
			whichState[i] = -1;
		}
		int maxIters = 200;
		initializeMatrices();
		int maxTimeStep = 501;
//		int[] observations = new int[Math.min(maxTimeStep, duck.GetSeqLength())];
//		for (int i = 0; i<observations.length;i++)
//		{
//			observations[i]= transFormObservation(duck.GetAction(i));
//		}
		//Helper.writeToFile(observations, "observations.txt");
		makeHMM(duck, maxIters, maxTime, pDue);
	}
	
	
	
	
	
	
	private void initializeExistingActions() {
		int[] movHor = {Action.MOVE_EAST, Action.MOVE_WEST, Action.BIRD_STOPPED};
		int[] movVer = {Action.MOVE_DOWN, Action.MOVE_UP, Action.BIRD_STOPPED};
//		for (int i = 0; i < 3; i++)
//		{
//			for (int j = 0; j<3; j++)
//			{
				for (int x = 0; x < 3; x++)
				{
				
					for (int y = 0; y < 3; y++)
					{
//						if (((i!=2 && x !=2) || (x==2 && i == 2)) &&((j!=2 && y != 2) || (j == 2 && y == 2)))
//						{
							//int e = ((movHor[i]|movVer[j])<<4)+(x<<2)+y;
							int e = (x<<2)+y;
							this.existingActions.add(new Integer(e));
							//this.createActionFromInt(this.existingActions.size()-1).Print();
//						}
						
					}
//				}
//				
//			//}
//			}
		}
		
				
			
		
	}
	
	public int getSeqLength()
	{
		return this.alpha.length;
	}
	
	private void initializeMatrices()
	{
		double[][] rad = {{0.8, 0.11, 0.09}, {0.19, 0.8, 0.01}, {0.07, 0.13, 0.8}};	
		A = new double[NUMSTATES][NUMSTATES];
		B = new double[NUMSTATES][NUMOBSERVATION];
		pi = new double[NUMSTATES];
		Random ran = new Random();
		
		
		for (int i = 0; i<NUMSTATES; i++)
		{
			double sum = 0;
			for (int j = 0; j < NUMSTATES-1; j++)
			{
				double value = (1/((double)(NUMSTATES)+1.0))+ran.nextDouble()/500-ran.nextDouble()/500;
				sum  +=value;
				A[i][j] = value;
			}
			A[i][NUMSTATES-1]=1 - sum;
			if ((1-sum)<0)
				System.out.println("SHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIITTTTTTTTTTTTTTTTTTTTTT");
			//System.out.println(""+(1-sum));
		}
		//A = {{0.28, 0.22, 0.23, 0.27},{0.24, 0.26, 0.21, 0.29},{0.22, 0.28, 0.27, 0.23},{0.26, 0.24, 0.29, 0.21}};
		A = rad;
		
		for (int i = 0; i<NUMSTATES; i++)
		{
			double sum = 0;
			for (int j = 0; j < NUMOBSERVATION-1; j++)
			{
				double value = (1/((double)(this.NUMOBSERVATION+1)))+ran.nextDouble()/500-ran.nextDouble()/500;
				sum  +=value;
				B[i][j] = value;
				
			}
			B[i][NUMOBSERVATION-1]=1 - sum;
			//System.out.println(""+(1-sum));
			if ((1-sum)<0)
				System.out.println("SHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIITTTTTTTTTTTTTTTTTTTTTT");
		}
		
		
		double sum = 0;
		for (int i = 0; i < NUMSTATES-1;i++)
		{	
			double val = (1/((double)(NUMSTATES)+1.0))+ran.nextDouble()/100 - ran.nextDouble()/100;
			sum += val;
			pi[i] = val;
		}
		pi[NUMSTATES-1] = 1-sum;
	}

	public void makeHMM(Duck duck, Deadline pDue) {
		makeHMM(duck, 200, Integer.MAX_VALUE,pDue);
	}
	private void makeHMM(Duck duck, int maxInters, int maxTime, Deadline pDue) {
		double logProb = Double.NEGATIVE_INFINITY;
		double oldLogProb = Double.NEGATIVE_INFINITY;
		int iters = 0;
//		numErrors = 0;
//		if (numErrorsG > 2)
//		{
//			initializeMatrices();
//			System.out.println("New And shiny");
//			numErrorsG = 0;
//		}
		
		while (iters < maxInters && (logProb > oldLogProb||iters == 0) && (iters == 0 || pDue.TimeUntil()> 50 ))
		{
			try{
				alpha = new double[Math.min(duck.GetSeqLength(), maxTime)][NUMSTATES];
				double[] ct = alphaPass(duck, alpha, false);
				beta = betaPass(duck, ct);
				digamma = new double[alpha.length][NUMSTATES];
				double[][][] gammaij = new double[alpha.length][NUMSTATES][NUMSTATES];
				computeDiGamma(duck, alpha, beta, digamma, gammaij);
				if (pDue.TimeUntil()> 50)
					reestimate(digamma, gammaij, duck);
				else return;
				oldLogProb = logProb;
				logProb = computeLog(ct);
				iters++;
			}
			catch(NewOne e)
			{
				initializeMatrices();
				iters = 0;
				oldLogProb = Double.NEGATIVE_INFINITY;
				//System.out.println("New Shine");
			}
			
				
		}
		
		//System.out.println(""+iters);
	}
	private double[][] digamma;
	private double[][] alpha;
	private double[][] beta;
	
	
	private double computeLog(double[] c)
	{
		double logProb = 0.0;
		for (int i = 0; i< c.length; i++)
		{
			logProb+=Math.log(c[i]);
		}
		return -logProb;
	}
	
	private void reestimate(double[][] digamma,
			double[][][] gammaij, Duck duck) 
	{
		for (int i = 0; i < NUMSTATES; i++)
		{
			pi[i] = digamma[0][i];
		}
		
		for (int i = 0; i < NUMSTATES;i++)
		{
			for (int j = 0; j < NUMSTATES; j++)
			{
				double numer = 0;
				double denom = 0;
				for (int t = 0; t < digamma.length-1;t++)
				{
					numer += gammaij[t][i][j];
					denom += digamma[t][i];
				}
				A[i][j] = numer/denom;
//				if (denom == 0)
//					System.out.println("Shit1");
			}
		}
		
		for (int i = 0; i < NUMSTATES;i++)
		{
			for (int j = 0; j < NUMOBSERVATION; j++)
			{
				double numer = 0;
				double denom = 0;
				for (int t = 0; t < digamma.length-1;t++)
				{
					if (transFormObservation(duck.GetAction(t)) == j)
					{
						numer += digamma[t][i];
					}
					denom += digamma[t][i];
				}
				B[i][j] = numer/denom;
//				if (denom == 0)
//					System.out.println("Shit2");
			}
		}
		
	}

	private Vector<Integer> seenStates = new Vector<Integer>();
	private void computeDiGamma(Duck duck, double[][] alpha, double[][] beta, double[][] digamma, double[][][] gammaij)
	{
		for (int t = 0; t<alpha.length-1;t++)
		{
			double denom = 0.0;
			for (int i = 0; i < NUMSTATES;i++)
			{
				for (int j = 0; j < NUMSTATES;j++)
				{
					denom += alpha[t][i]*A[i][j]*B[j][transFormObservation(duck.GetAction(t+1))]*beta[t+1][j];
				}
			}
			
//			double sumDigamma = 0;
			for (int i = 0; i < NUMSTATES;i++)
			{
				digamma[t][i]=0.0;
				for (int j = 0; j < NUMSTATES;j++)
				{
					gammaij[t][i][j] = (alpha[t][i]*A[i][j]*B[j][transFormObservation(duck.GetAction(t+1))]*beta[t+1][j])/denom;
					digamma[t][i] += gammaij[t][i][j];
//					sumDigamma+=digamma[t][i];
				}
//				if (digamma[t][i]>0.99 && !seenStates.contains(new Integer(i)))
//				{
//					seenStates.add(new Integer(i));
//					if (seenStates.size()==3)
//					{
//						for (int x = 0; x < NUMSTATES; x++)
//						{
//							A[i][x] = 0;
//						}
//						
//					}
//				}
					
			}
			
//			if (denom == 0 || sumDigamma == 0)
//			{
//				gammaij[t] = gammaij[t-1];
//				digamma[t] = digamma[t-1];
//			}
				
		}
	}

	private double[] alphaPass(Duck duck, double[][] alpha, boolean ignore) throws NewOne {
		double[] c = new double[alpha.length];
		double c0 = 0;
		Action h = duck.GetAction(0);
		int oberservation = transFormObservation(h);
		for (int i = 0; i< NUMSTATES;i++)
		{	
			
			alpha[0][i] = this.pi[i]*this.B[i][oberservation];
			c0 += alpha[0][i];
		}
		c0 = 1/c0;
		c[0]=c0;
		for (int i = 0; i< NUMSTATES;i++)
		{
			alpha[0][i] = c0*alpha[0][i];
		}
		
		
		for (int t = 1; t < alpha.length; t++)
		{
			c0 = 0;
			h = duck.GetAction(t);
			oberservation = transFormObservation(h);
			for (int i = 0; i < NUMSTATES; i++)
			{
				alpha[t][i]= 0.0;
				
				for (int j = 0; j < NUMSTATES; j++)
				{
					alpha[t][i]= alpha[t][i]+ alpha[t-1][j]*A[j][i];
				}
				//Vereinzelte seltene Beobachtungen ignorieren
				
				alpha[t][i]=alpha[t][i]*this.B[i][oberservation];
				c0 += alpha[t][i];
			}
			if ( c0 == 0 && ignore)
			{
				alpha[t] = alpha[t-1];
				c[t]=c[t-1];
				//System.out.println("ERROR");
				//numErrors++;
			}
			else
			{	
				if (c0 == 0 && !ignore) 
					throw new NewOne();
				c0 = 1/c0;
				
				c[t]=c0;
				for (int i = 0; i < NUMSTATES; i++)
				{
					alpha[t][i] = c0*alpha[t][i];
				}
			}
			
			
		}
		return c;
	}
	
	private double[][] betaPass(Duck duck, double[] c)
	{
		double[][] beta = new double[c.length][NUMSTATES];
		
		
		for (int i = 0; i<NUMSTATES;i++)
		{
			beta[c.length-1][i] = c[c.length-1];
		}
		
		
		for (int t = c.length-2;t>=0;t--)
		{
//			boolean oneGZero = false;
			
			for(int i = 0; i < NUMSTATES;i++)
			{
				beta[t][i] = 0.0;
				for (int j = 0; j < NUMSTATES;j++)
				{
					beta[t][i] = beta[t][i]+
							A[i][j]*B[j][transFormObservation(duck.GetAction(t+1))]*beta[t+1][j];
				}
				beta[t][i] = beta[t][i]*c[t];
//				if (beta[t][i]>0)
//					oneGZero = true;
			}
//			if (!oneGZero)
//				beta[t]=beta[t+1];
			
			
		}
		
		return beta;
	}
	
	private int transFormObservation(Action h)
	{
		//int ret = (h.mMovement<<4)+(h.mHorz<<2)+h.mVert;
		int ret = (h.mHorz<<2)+h.mVert;
		if (this.existingActions.indexOf(ret) < 0)
		{
			System.out.println("ERROR");
		}
		return this.existingActions.indexOf(ret);
	}

	public HMM()
	{
		
	}
	
	public double[][] getA()
	{
		return A;
	}
	
	public double[][] getB()
	{
		return B;
	}
	
	public double[] getPi()
	{
		return pi;
	}
	
	public double getNextMostLikelyAction(Duck duck, Action ret, boolean notShoot)
	{
		double[] predict = alphaPassPrediction(duck);
		int maxActionInd = 0;
		Vector<Double[]> mostLikelyObs = new Vector<Double[]>(); 
		for (int i = 0; i < predict.length; i++)
		{
			for (int j = 0; j < NUMSTATES; j++)
			{
				for (int b = 0; b < NUMOBSERVATION; b++)
				{
					double prob = predict[i]*A[i][j]*B[j][b];
					Double[] ans = {(double) b,prob, (double) i}; 
					mostLikelyObs.add(ans);
				}
			}
			if (predict[i] > predict[maxActionInd])
			{
				maxActionInd = i;
			}
		}
//		if (predict[maxActionInd]<0.9)
//			return Action.cDontShoot;
//		
		double[] specB = B[maxActionInd];
		int actionInd = 0;
		for (int i = 1; i < specB.length; i++)
		{
			if (specB[i]>specB[actionInd])
				actionInd = i;
		}
//		if ((predict[maxActionInd]*B[maxActionInd][actionInd])<probability)//0.6)
//		{
//			//this.isConverged--;
//			return Action.cDontShoot;
//		}
		//System.out.println("Shoooot");
		
		int mostLikelyObsIndex = 0;	
		for (int i = 1; i < mostLikelyObs.size(); i++)
		{
			if (mostLikelyObs.get(mostLikelyObsIndex)[1] < mostLikelyObs.get(i)[1])
				mostLikelyObsIndex = i;
		}
		if (notShoot && this.validStateSeq)
		{
			if (hasMigrating())
			{
					if (this.whichState[(int) mostLikelyObs.get(mostLikelyObsIndex)[2].longValue()]!=MIGRATING || (this.whichState[(int) mostLikelyObs.get(mostLikelyObsIndex)[2].longValue()]==MIGRATING && duck.GetLastAction().mMovement != duck.GetAction(duck.GetSeqLength()-2).mMovement))
					{
						ret = Action.cDontShoot;
						return 0.0;
					
					}
			}
			else
			{
				if (this.whichState[(int) mostLikelyObs.get(mostLikelyObsIndex)[2].longValue()]!=FEIGNING_DEATH || (this.whichState[(int) mostLikelyObs.get(mostLikelyObsIndex)[2].longValue()]==FEIGNING_DEATH && duck.GetLastAction().mMovement != duck.GetAction(duck.GetSeqLength()-2).mMovement))
				{
					ret = Action.cDontShoot;
					return 0.0;
				
				}
			}
		}
		else if (!this.validStateSeq)
		{
			if (duck.GetLastAction().mMovement != duck.GetAction(duck.GetSeqLength()-2).mMovement)
			{
				ret = Action.cDontShoot;
				return 0.0;
			
			}
		}
		//System.out.println((predict[maxActionInd]*B[maxActionInd][actionInd]));
		//Action a= createActionFromInt(actionInd);
		Action a= createActionFromInt((int)mostLikelyObs.get(mostLikelyObsIndex)[0].floatValue());
		a.mMovement = duck.GetLastAction().mMovement;
		a.mBirdNumber = duck.GetLastAction().mBirdNumber;
		//a.Print();
		ret.mHorz = a.mHorz;
		ret.mMovement = a.mMovement;
		ret.mVert = a.mVert;
		ret.mBirdNumber = a.mBirdNumber;
		//return (predict[maxActionInd]*B[maxActionInd][actionInd]);
		return mostLikelyObs.get(mostLikelyObsIndex)[1];
	}
	
	public Action predictNextAction(Duck duck)
	{
		double pol = 0;
		for (int i = 0; i < NUMSTATES; i++)
		{
			pol += alpha[alpha.length-1][i];
		}
		double[] gammaT = new double[NUMSTATES]; 
				
		for (int i = 0; i < NUMSTATES; i++)
		{
			gammaT[i] = (alpha[alpha.length-1][i]*beta[alpha.length-1][i])/pol;
		}
		int indMax = 0;
		
		for (int i = 1; i < NUMSTATES; i++)
		{
			if (gammaT[indMax]<gammaT[i])
				indMax = i;
		}
		double[] specB = B[indMax];
		
		int maxIndObs = 0;
		for (int i = 1; i < NUMOBSERVATION; i++)
		{
			if (specB[i] > specB[maxIndObs])
				maxIndObs = i;
		}
		Action finish = this.createActionFromInt(maxIndObs);
		System.out.println(maxIndObs);
		System.out.println(transFormObservation(duck.GetLastAction()));
		finish.mMovement = duck.GetLastAction().mMovement;
		return finish;
	}
	
	private double[] alphaPassPrediction(Duck duck) {
		//double[] predict = new double[NUMOBSERVATION];
		double[][] alpha = new double[duck.GetSeqLength()][NUMSTATES];
		//double[] c;
		try{
			 this.alphaPass(duck, alpha, true);
		}
		catch(NewOne e)
		{
			throw new NullPointerException();
		}
		
		double[] endAlpha = alpha[alpha.length-1];
		
		return endAlpha;
	}
	
	private Action createActionFromInt(int o)
	{
		String s = Integer.toBinaryString(this.existingActions.get(o));
		
		int horz = 0;
		int vert = 0;
		int mov = 0;
		if (s.length() == 1)
		{
			vert = Integer.parseInt(s);
		}
		else if(s.length() == 2)
		{
			vert = Integer.parseInt(s,2);
		}
		else if(s.length() >= 3 && s.length() <=4)
		{
			String h = s.substring(s.length()-2, s.length());
			String b = s.substring(0, s.length()-2);
			vert = Integer.parseInt(h,2);
			horz = Integer.parseInt(b,2);
		}
		else if (s.length() > 4)
		{
			horz = Integer.parseInt(s.substring(s.length()-2, s.length()),2);
			vert = Integer.parseInt(s.substring(s.length()-4, s.length()-2),2);
			mov = Integer.parseInt(s.substring(0, s.length()-4),2);
		}
		return new Action(0, horz, vert, mov);
	}
	
	public boolean isConverged()
	{
		return (this.isConverged>0);
	}




	

	public double howLikelyIsObservation(Duck duck, int seqLength) {
		int obs = this.transFormObservation(duck.GetAction(0));
		//int firstState = 0;
//		for (int i = 1; i < NUMSTATES; i++)
//		{
//			if (B[i][obs] > B[firstState][obs])
//			{
//				firstState = i;
//			}
//		}
		double[][] alpha = new double[seqLength][NUMSTATES];
		double c0 = 0;
		for (int i = 0; i<NUMSTATES;i++)
		{
			//if (i == firstState) 
			alpha[0][i] = B[i][obs];
			c0+=alpha[0][i];
			
		}
		for (int i = 0; i < NUMSTATES; i++)
		{
			alpha[0][i] = c0*alpha[0][i];
		}
		
		
		
		int wrongOnes = 0;
		double todivide = c0;
		
		for (int t = 1; t < alpha.length; t++)
		{
			c0 = 0;
			
			Action h = duck.GetAction(t);
			int oberservation = transFormObservation(h);
			for (int i = 0; i < NUMSTATES; i++)
			{
				alpha[t][i]= 0.0;
				
				for (int j = 0; j < NUMSTATES; j++)
				{
					alpha[t][i]= alpha[t][i]+ alpha[t-1][j]*A[j][i];
				}
				//Vereinzelte seltene Beobachtungen ignorieren
				
				alpha[t][i]=alpha[t][i]*this.B[i][oberservation];
				c0 += alpha[t][i];
			}
			if ( c0 == 0 )
			{
				alpha[t] = alpha[t-1];
				wrongOnes++;
				if (wrongOnes>6)
					return 0;
				//System.out.println("ERROR");
				//numErrors++;
			}
			else
			{
				c0 = 1/c0;
				todivide*= c0;
				
				for (int i = 0; i < NUMSTATES; i++)
				{
					alpha[t][i] = c0*alpha[t][i];
				}
			}
			
			
			
		}
		
		double sum = 0;
		for (int i = 0; i<NUMSTATES; i++)
		{
			sum+=((alpha[alpha.length-1][i])/todivide);
		}
		//System.out.println(sum);
		if ((new Double(sum/todivide).equals(Double.POSITIVE_INFINITY)))
				System.out.println("Blah");
		return (sum);
		
	}
	
	public Action predictNextActionGood(Duck duck)
	{
		int state = getMostProbableState();
		int column = getMostProbableActionForState(state);
		Action action = createActionFromInt(column);
		
		action.mMovement = duck.GetLastAction().mMovement;
		this.probabilityNextAction *= B[state][column];
		return action;
		
	}
	
	private int getMostProbableState()
	{
		double probability = 0;
		int stateCurrentStep = 0;
		
		//get the state the bird is in now
		for (int i = 0; i < NUMSTATES; i++)
		{
			if (digamma[digamma.length - 2][i] > probability)
			{
				probability = digamma[digamma.length - 2][i];
				stateCurrentStep = i;						
			}
		}
		//get the state the bird will be in the next step
		probability = 0;
		int stateNextStep = 0;
		for (int i = 0; i < NUMSTATES; i++)
		{
			if (A[stateCurrentStep][i] > probability)
			{
				probability = A[stateCurrentStep][i];
				stateNextStep = i;
			}
		}
		this.probabilityNextAction = digamma[digamma.length - 2][stateCurrentStep] * A[stateCurrentStep][stateNextStep];
		return stateNextStep;
	}
	private double probabilityNextAction = 0;
	
	private int getMostProbableActionForState(int state)
	{
		double probability = 0;
		int action = 0;
		
		for (int i = 0; i < NUMOBSERVATION; i++)
		{
			if (B[state][i] > probability)
			{
				probability = B[state][i];
				action = i;						
			}
		}
		return action;
	}
	
	public boolean figureOutStates()
	{
		for (int i = 0; i < this.whichState.length; i++)
		{
			this.whichState[i] = -1;
		}
		//double probs[] = new double[4];
		double probs[][] = new double[NUMSTATES][4];
		for (int i = 0; i < NUMSTATES; i++)
		{
			
			 int highestObservation = 0;
			for (int j = 1; j < NUMOBSERVATION; j++)
			{
				if (B[i][highestObservation] < B[i][j])
					highestObservation = j;
			}
			
				for (int x = 0; x < this.typMax.get(MIGRATING).size();x++)
				{
//					if (this.typMax.get(MIGRATING).get(x)==highestObservation)
//					{
					probs[i][MIGRATING]+= B[i][this.typMax.get(MIGRATING).get(x)];
//						this.whichState[i] = MIGRATING;
//						break;
//					}
					
						
				}
				if (probs[i][MIGRATING] > 0.9)
				{
					this.whichState[i] = MIGRATING;
					continue;
				}
					
				for (int x = 0; x < this.typMax.get(FEIGNING_DEATH).size();x++)
				{
					probs[i][FEIGNING_DEATH]+= B[i][this.typMax.get(FEIGNING_DEATH).get(x)];
//					if (this.typMax.get(FEIGNING_DEATH).get(x)==highestObservation)
//					{
//						this.whichState[i] = FEIGNING_DEATH;
//						break;
//					}
					
						
				}
				if (probs[i][FEIGNING_DEATH] > 0.9)
				{
					this.whichState[i] = FEIGNING_DEATH;
					continue;
				}
//			}
//			else
//			{
				for (int x = 0; x < this.typMax.get(PANICKING).size();x++)
				{
//					if (this.typMax.get(PANICKING).get(x)==highestObservation)
//					{
//						this.whichState[i] = PANICKING;
//						break;
//					}
					probs[i][PANICKING]+= B[i][this.typMax.get(PANICKING).get(x)];
				}
				if (probs[i][PANICKING] > 0.7)
				{
					
					this.whichState[i] = PANICKING;
					continue;
				}
				for (int x = 0; x < this.typMax.get(QUACKING).size();x++)
				{
//					if (this.typMax.get(QUACKING).get(x)==highestObservation)
//					{
//						this.whichState[i] = QUACKING;
//						break;
//					}
					probs[i][QUACKING]+= B[i][this.typMax.get(QUACKING).get(x)];
				}
				if (probs[i][QUACKING] > 0.7)
				{
					this.whichState[i] = QUACKING;
					continue;
				}
			//}	
//				int maxIndex = 0;
//				System.out.println("Hups");
//				for (int x = 1; x < probs.length;x++)
//				{
//					if (probs[i][maxIndex]<probs[i][x])
//						maxIndex = x;
//				}
//				this.whichState[i] = maxIndex;
		}
		for (int i = 0; i < NUMSTATES; i++)
		{
			for (int x = i+1; x < NUMSTATES; x++)
			{
				if (this.whichState[x] == this.whichState[i] || this.whichState[i]==-1)
				{
					this.validStateSeq = false;
					return false;
//					int nextHighestX = 0;
//					int nextHighestI = 0;
//					for (int l = 1; l < 4; l++)
//					{
//						if(probs[x][nextHighestX] < probs[x][l] && l!=this.whichState[i])
//							nextHighestX = l;
//						if(probs[i][nextHighestI] < probs[i][l] && l!=this.whichState[i])
//							nextHighestI = l;
//					}
//					if (probs[i][(int) this.whichState[i]]- probs[x][(int) this.whichState[i]] < 0.1 || 
//					             probs[i][nextHighestI] > probs[x][nextHighestX])
//						this.whichState[x] = nextHighestX;
//					else
//						this.whichState[i] = nextHighestI;
//					
//					i = 0;
						
				}
			}
		}
		validStateSeq = true;
		return true;
	}
	
	public double[] getStates()
	{
		return this.whichState;
	}
	
	private boolean hasMigrating()
	{
		if (!this.validStateSeq) return false;
		for (int i = 0; i < NUMSTATES; i++)
		{
			if (this.whichState[i]==MIGRATING)
				return true;
		}
		return false;
	}
}
